package com.ktdaddy.config.shiro.realm;

import com.ktdaddy.enums.IsLock;
import com.ktdaddy.pojo.Kernel;
import com.ktdaddy.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Objects;

/**
 * @author kdaddy@163.com
 * @date 2021/4/21 22:19
 */
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private RealmHelper realmHelper;

    /**
     * 限定这个 Realm 只处理 UsernamePasswordToken
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    /**
     * 查询数据库，将获取到的用户安全数据封装返回
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 从 AuthenticationToken 中获取当前用户
        String kernelName = (String) token.getPrincipal();
        // 查询数据库获取用户信息，此处使用 Map 来模拟数据库
        Kernel kernel = userService.getKernelByKernelName(kernelName);
        // 用户不存在
        if (Objects.isNull(kernel)) {
           throw new UnknownAccountException("用户不存在！");
        }

        // 用户被锁定
        if (kernel.getIsLock().equals(IsLock.YES.getCode())) {
            throw new LockedAccountException("该用户已被锁定,暂时无法登录！");
        }

        // 获取加密盐
        ByteSource credentialsSalt = ByteSource.Util.bytes(kernel.getKernelName() + kernel.getSalt());
        /**
         * 将获取到的用户数据封装成 AuthenticationInfo 对象返回，此处封装为 SimpleAuthenticationInfo 对象。
         *  参数1. 认证的实体信息，可以是从数据库中获取到的用户实体类对象或者用户名
         *  参数2. 查询获取到的登录密码
         *  参数3. 盐值
         *  参数4. 当前 Realm 对象的名称，直接调用父类的 getName() 方法即可
         */
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(kernel,
                kernel.getPassword(), getName());
        authenticationInfo.setCredentialsSalt(credentialsSalt);
        return authenticationInfo;
    }

    /**
     * 查询数据库，将获取到的用户的角色及权限信息返回
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return realmHelper.buildCommonInfo();
    }
}
